﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AG3D
{
    class AG3D
    {
        public string texto;
        public int poblacion;
        Random generadorAleatorio = new Random();
        public List<List<int[]>> pueblo = new List<List<int[]>>();
        string[] instrucciones = new string[] { "arriba", "abajo", "izquierda", "derecha", "dentro", "fuera" };


        public void pruebas()
        {

            int entero1 = generadorAleatorio.Next(poblacion);
            int entero2 = generadorAleatorio.Next(poblacion);

            System.Diagnostics.Debug.WriteLine("P1 = " + pueblo[entero1].Count + " P2 = " + pueblo[entero2].Count);
            List<int[]> cruzado = this.cruzar(pueblo[entero1], pueblo[entero2]);


            System.Diagnostics.Debug.WriteLine("P1 + P2 = " + cruzado.Count);

            int contador = 1;
            //foreach (List<int[]> a in pueblo)
            //{

            //    System.Diagnostics.Debug.WriteLine(contador++ + ":" + a.Count);

            //    girarIzquierda(a);

            //}
        }
        public AG3D(string texto, int poblacion)
        {
            this.texto = texto;
            this.poblacion = poblacion;
        }

        public void generarPoblacionInicial()
        {

            for (int i = 0; i < this.poblacion; i++)
            {
                pueblo.Add(this.generarSolucionAleatoriaGenerica3D(new List<int[]>(), new int[] { 0, 0, 0 }, this.texto.Length));

            }
        }

        public void seleccion()
        {

            List<List<int[]>> p1 = new List<List<int[]>>();
            int participante1 = 0;
            int participante2 = 0;

            while (p1.Count < this.poblacion)
            {
                participante1 = generadorAleatorio.Next(this.poblacion);
                participante2 = generadorAleatorio.Next(this.poblacion);

                if (evaluarCamino3D(pueblo[participante1]) < evaluarCamino3D(pueblo[participante2]))
                {
                    p1.Add(pueblo[participante1]);
                }
                else
                {
                    p1.Add(pueblo[participante2]);
                }
            }//fin while

            pueblo = new List<List<int[]>>();
            pueblo.AddRange(p1);


        }

        public void cruzamiento()
        {
            List<List<int[]>> p1 = new List<List<int[]>>();
            int participante1 = 0;
            int participante2 = 0;
            int i = 1;

            while (p1.Count < this.poblacion)
            {
                participante1 = generadorAleatorio.Next(this.poblacion);
                participante2 = generadorAleatorio.Next(this.poblacion);

                p1.Add(this.cruzar(pueblo[participante1], pueblo[participante2]));

               // System.Diagnostics.Debug.WriteLine(i++ + "," + poblacion);
            }//fin while

            pueblo = new List<List<int[]>>();
            pueblo.AddRange(p1);



        }


        public List<int[]> generarSolucionAleatoriaGenerica3D(List<int[]> camino, int[] coordenadaInicial, int tamanoFinal)
        {


            camino.Add(coordenadaInicial);

            List<int[]> copiaCamino = new List<int[]>();
            copiaCamino.AddRange(camino);
            int[] copiaCoordenadaInicial = coordenadaInicial;

            coordenadaInicial = generarCoordenadaNueva3D(coordenadaInicial);
            int n = 0;


            while (camino.Count < tamanoFinal)
            {

                n++;

                while (contieneGenerico3D(camino, coordenadaInicial))
                {
                    if (estaBloqueado3D(camino))
                        break;

                    coordenadaInicial = generarCoordenadaNueva3D((int[])camino[camino.Count - 1]);
                }


                if (estaBloqueado3D(camino))
                {
                    camino = new List<int[]>();
                    camino.AddRange(copiaCamino);

                    coordenadaInicial = copiaCoordenadaInicial;
                }
                else
                {
                    camino.Add(coordenadaInicial);
                }

                if (n > 1000)
                {
                    // Console.WriteLine("Camino bloqueado, generando camino nuevo... " + camino.Count + " = " + tamanoFinal);


                    camino = new List<int[]>();

                    camino = this.generarSolucionAleatoriaGenerica3D(camino, new int[] { 0, 0, 0 }, this.texto.Length);
                    break;

                    //this.generar2d(camino, "HPHPHHPHP", "YA WEEEEEY");
                }

            }


            return camino;


        }//fin metodo generarSolucionAleatoriaGenerica

        private int[] generarCoordenadaNueva3D(int[] coordenada)
        {

            int[] cNueva = new int[3];

            int numAleatorio = this.generadorAleatorio.Next(6);

            if (numAleatorio == 0)
            {
                cNueva[0] = coordenada[0] + 1;
                cNueva[1] = coordenada[1];
                cNueva[2] = coordenada[2];

            }
            else if (numAleatorio == 1)
            {
                cNueva[0] = coordenada[0] - 1;
                cNueva[1] = coordenada[1];
                cNueva[2] = coordenada[2];

            }
            else if (numAleatorio == 2)
            {
                cNueva[0] = coordenada[0];
                cNueva[1] = coordenada[1] + 1;
                cNueva[2] = coordenada[2];

            }
            else if (numAleatorio == 3)
            {
                cNueva[0] = coordenada[0];
                cNueva[1] = coordenada[1] - 1;
                cNueva[2] = coordenada[2];

            }
            else if (numAleatorio == 3)
            {
                cNueva[0] = coordenada[0];
                cNueva[1] = coordenada[1];
                cNueva[2] = coordenada[2] + 1;

            }
            else
            {
                cNueva[0] = coordenada[0];
                cNueva[1] = coordenada[1];
                cNueva[2] = coordenada[2] - 1;

            }

            return cNueva;
        }//  fin generar coordenada aleatoria

        private bool estaBloqueado3D(List<int[]> camino)
        {

            int[] coordenada = (int[])camino[camino.Count - 1];

            int[] coordenada1 = new int[3];
            int[] coordenada2 = new int[3];
            int[] coordenada3 = new int[3];
            int[] coordenada4 = new int[3];
            int[] coordenada5 = new int[3];
            int[] coordenada6 = new int[3];

            coordenada1[0] = coordenada[0];
            coordenada1[1] = coordenada[1] + 1;
            coordenada1[2] = coordenada[2];

            coordenada2[0] = coordenada[0];
            coordenada2[1] = coordenada[1] - 1;
            coordenada2[2] = coordenada[2];

            coordenada3[0] = coordenada[0] + 1;
            coordenada3[1] = coordenada[1];
            coordenada3[2] = coordenada[2];

            coordenada4[0] = coordenada[0] - 1;
            coordenada4[1] = coordenada[1];
            coordenada4[2] = coordenada[2];

            coordenada5[0] = coordenada[0];
            coordenada5[1] = coordenada[1];
            coordenada5[2] = coordenada[2] + 1;

            coordenada6[0] = coordenada[0];
            coordenada6[1] = coordenada[1];
            coordenada6[2] = coordenada[2] - 1;


            return (contieneGenerico3D(camino, coordenada1) && contieneGenerico3D(camino, coordenada2)
                && contieneGenerico3D(camino, coordenada3) && contieneGenerico3D(camino, coordenada4)
                && contieneGenerico3D(camino, coordenada5) && contieneGenerico3D(camino, coordenada6));


        }//fin estaBloqueado

        private bool contieneGenerico3D(List<int[]> camino, int[] c)
        {

            bool bandera = false;

            foreach (int[] i in camino)
            {

                if (i[0] == c[0] &&
                    i[1] == c[1] &&
                    i[2] == c[2])
                {
                    bandera = true;

                }

            }

            return bandera;

        }//fin metodo contieneGenerico

        public int evaluarCamino3D(List<int[]> camino)
        {

            int[] primero = new int[3];
            int[] siguiente = new int[3];
            int energia = 0;




            for (int j = 0; j < camino.Count; j++)
            {

                primero = (int[])camino[j];

                for (int i = j + 2; i < camino.Count - 1 + 1; i++)
                {
                    siguiente = (int[])camino[i];
                    if (distancia3D(primero[0], primero[1], primero[2], siguiente[0], siguiente[1],siguiente[2], j, i) == 1)
                    {
                        energia--;

                    }

                }

                //Console.WriteLine ("AY MI DIOS");
            }

            return energia;
            //contador++;

        }//fin funcionEnergia

        private int distancia3D(int x1, int y1, int z1, int x2, int y2, int z2, int letra1, int letra2)
        {

            if (letra2 >= texto.Length)
                return 0;

            int e = 0;

            if ((texto[letra1] == texto[letra2])
                && (texto[letra1] == 'H' && texto[letra2] == 'H'))
            {
                if ((Math.Pow(x1 - x2, 2) + Math.Pow(y1 - y2, 2) + Math.Pow(z1 - z2, 2)) == 1)
                    e = 1;

            }



            return e;

        }//fin metodo distancia

        public List<int[]> girarIzquierda(List<int[]> camino)
        {
            List<int[]> girado = new List<int[]>();

          //  int contador = 0;

            int[] coordenadaReferencia = new int[3];

            int[] coordenadaNueva = new int[3];

            girado.Add(camino[0]);

            

            for (int i = 1; i < camino.Count; i++)
            {
                try
                {
                    coordenadaReferencia = camino[i - 1];
                    coordenadaNueva = girado[i - 1];
                }
                catch
                {
                    System.Diagnostics.Debug.WriteLine("Tamaño camino: " + camino.Count + " Tamaño girado: " + girado.Count);
                    System.Environment.Exit(0);
                }

                if ((coordenadaReferencia[0] + 1) == camino[i][0])// +X -> -Z
                {
                    girado.Add(new int[] { coordenadaNueva[0], coordenadaNueva[1], coordenadaNueva[2] - 1});
                }
                else if ((coordenadaReferencia[0] - 1) == camino[i][0])//-X -> +Z
                {

                    girado.Add(new int[] { coordenadaNueva[0], coordenadaNueva[1], coordenadaNueva[2] + 1 });
                }
                else if ((coordenadaReferencia[1] + 1) == camino[i][1])//+Y -> +Y
                {
                    girado.Add(new int[] { coordenadaNueva[0], coordenadaNueva[1] + 1, coordenadaNueva[2] });

                }
                else if ((coordenadaReferencia[1] - 1) == camino[i][1])//-Y -> -Y
                {
                    girado.Add(new int[] { coordenadaNueva[0], coordenadaNueva[1] - 1, coordenadaNueva[2]});

                }
                else if ((coordenadaReferencia[2] + 1) == camino[i][2])//+Z -> +X
                {
                    girado.Add(new int[] { coordenadaNueva[0] + 1, coordenadaNueva[1], coordenadaNueva[2]});

                }
                else if ((coordenadaReferencia[2] - 1) == camino[i][2])//-Z -> -X
                {
                    girado.Add(new int[] { coordenadaNueva[0] - 1, coordenadaNueva[1], coordenadaNueva[2] });

                }


            }
                return girado;
            
        }

        public List<int[]> girarAbajo(List<int[]> camino)
        {
            List<int[]> girado = new List<int[]>();

            //  int contador = 0;

            int[] coordenadaReferencia = new int[3];

            int[] coordenadaNueva = new int[3];

            girado.Add(camino[0]);



            for (int i = 1; i < camino.Count; i++)
            {
                coordenadaReferencia = camino[i - 1];
                coordenadaNueva = girado[i - 1];

                if ((coordenadaReferencia[0] + 1) == camino[i][0])// +X -> +X
                {
                    girado.Add(new int[] { coordenadaNueva[0] + 1, coordenadaNueva[1], coordenadaNueva[2] });
                }
                else if ((coordenadaReferencia[0] - 1) == camino[i][0])//-X -> -X
                {

                    girado.Add(new int[] { coordenadaNueva[0] - 1, coordenadaNueva[1], coordenadaNueva[2]  });
                }
                else if ((coordenadaReferencia[1] + 1) == camino[i][1])//+Y -> -Z
                {
                    girado.Add(new int[] { coordenadaNueva[0], coordenadaNueva[1], coordenadaNueva[2]  - 1});

                }
                else if ((coordenadaReferencia[1] - 1) == camino[i][1])//-Y -> +Z
                {
                    girado.Add(new int[] { coordenadaNueva[0], coordenadaNueva[1], coordenadaNueva[2] + 1 });

                }
                else if ((coordenadaReferencia[2] + 1) == camino[i][2])//+Z -> +Y
                {
                    girado.Add(new int[] { coordenadaNueva[0], coordenadaNueva[1] + 1, coordenadaNueva[2] });

                }
                else if ((coordenadaReferencia[2] - 1) == camino[i][2])//-Z -> -Y
                {
                    girado.Add(new int[] { coordenadaNueva[0], coordenadaNueva[1] - 1, coordenadaNueva[2] });

                }


            }

            return girado;

        }

        public List<int[]> girarHorario(List<int[]> camino)
        {
            List<int[]> girado = new List<int[]>();

            //  int contador = 0;

            int[] coordenadaReferencia = new int[3];

            int[] coordenadaNueva = new int[3];

            girado.Add(camino[0]);



            for (int i = 1; i < camino.Count; i++)
            {
                coordenadaReferencia = camino[i - 1];
                coordenadaNueva = girado[i - 1];

                if ((coordenadaReferencia[0] + 1) == camino[i][0])// +X -> -Y
                {
                    girado.Add(new int[] { coordenadaNueva[0], coordenadaNueva[1] - 1, coordenadaNueva[2] });
                }
                else if ((coordenadaReferencia[0] - 1) == camino[i][0])//-X -> +Y
                {

                    girado.Add(new int[] { coordenadaNueva[0], coordenadaNueva[1] + 1, coordenadaNueva[2] });
                }
                else if ((coordenadaReferencia[1] + 1) == camino[i][1])//+Y -> +X
                {
                    girado.Add(new int[] { coordenadaNueva[0] + 1, coordenadaNueva[1], coordenadaNueva[2] });

                }
                else if ((coordenadaReferencia[1] - 1) == camino[i][1])//-Y -> -X
                {
                    girado.Add(new int[] { coordenadaNueva[0] - 1, coordenadaNueva[1], coordenadaNueva[2] });

                }
                else if ((coordenadaReferencia[2] + 1) == camino[i][2])//+Z -> +Z
                {
                    girado.Add(new int[] { coordenadaNueva[0], coordenadaNueva[1], coordenadaNueva[2] + 1 });

                }
                else if ((coordenadaReferencia[2] - 1) == camino[i][2])//-Z -> -Z
                {
                    girado.Add(new int[] { coordenadaNueva[0], coordenadaNueva[1], coordenadaNueva[2] - 1 });

                }


            }

            return girado;

        }

        public List<int[]> girarAntihorario(List<int[]> camino)
        {
            List<int[]> girado = new List<int[]>();

            //  int contador = 0;

            int[] coordenadaReferencia = new int[3];

            int[] coordenadaNueva = new int[3];

            girado.Add(camino[0]);



            for (int i = 1; i < camino.Count; i++)
            {
                coordenadaReferencia = camino[i - 1];
                coordenadaNueva = girado[i - 1];

                if ((coordenadaReferencia[0] + 1) == camino[i][0])// +X -> +Y
                {
                    girado.Add(new int[] { coordenadaNueva[0], coordenadaNueva[1] + 1, coordenadaNueva[2] });
                }
                else if ((coordenadaReferencia[0] - 1) == camino[i][0])//-X -> -Y
                {

                    girado.Add(new int[] { coordenadaNueva[0], coordenadaNueva[1] - 1, coordenadaNueva[2] });
                }
                else if ((coordenadaReferencia[1] + 1) == camino[i][1])//+Y -> -X
                {
                    girado.Add(new int[] { coordenadaNueva[0] - 1, coordenadaNueva[1], coordenadaNueva[2] });

                }
                else if ((coordenadaReferencia[1] - 1) == camino[i][1])//-Y -> +X
                {
                    girado.Add(new int[] { coordenadaNueva[0] + 1, coordenadaNueva[1], coordenadaNueva[2] });

                }
                else if ((coordenadaReferencia[2] + 1) == camino[i][2])//+Z -> +Z
                {
                    girado.Add(new int[] { coordenadaNueva[0], coordenadaNueva[1], coordenadaNueva[2] + 1 });

                }
                else if ((coordenadaReferencia[2] - 1) == camino[i][2])//-Z -> -Z
                {
                    girado.Add(new int[] { coordenadaNueva[0], coordenadaNueva[1], coordenadaNueva[2] - 1 });

                }


            }

            return girado;

        }

        private bool esCompatible(List<int[]> padre1, List<int[]> padre2, string instruccion)
        {
            bool bandera = true;


            List<int[]> elNuevoSer = new List<int[]>();

            elNuevoSer.AddRange(padre1);

            int[] ultimaCoordenada = elNuevoSer[elNuevoSer.Count - 1];
            int[] coordenadaAnteriorPadre2 = padre2[0];

            // Console.WriteLine("Padre1: " + padre1.Count + ", Padre2: " + padre2.Count);


            if (instruccion == "arriba")
            {

                elNuevoSer.Add(new int[] { ultimaCoordenada[0], ultimaCoordenada[1] + 1, ultimaCoordenada[2] });

            }
            else if (instruccion == "abajo")
            {
                elNuevoSer.Add(new int[] { ultimaCoordenada[0], ultimaCoordenada[1] - 1, ultimaCoordenada[2] });

            }
            else if (instruccion == "derecha")
            {
                elNuevoSer.Add(new int[] { ultimaCoordenada[0] + 1, ultimaCoordenada[1], ultimaCoordenada[2] });

            }
            else if(instruccion == "izquierda")
            {
                elNuevoSer.Add(new int[] { ultimaCoordenada[0] - 1, ultimaCoordenada[1], ultimaCoordenada[2] });

            }
            else if (instruccion == "dentro")
            {
                elNuevoSer.Add(new int[] { ultimaCoordenada[0] + 1, ultimaCoordenada[1], ultimaCoordenada[2] + 1 });

            }
            else if (instruccion == "fuera")
            {
                elNuevoSer.Add(new int[] { ultimaCoordenada[0] + 1, ultimaCoordenada[1], ultimaCoordenada[2] - 1});

            }


            int contador = 0;
            foreach (int[] i in padre2)
            {
                if (contador++ == 0)
                    continue;

                coordenadaAnteriorPadre2 = padre2[contador - 2];
                ultimaCoordenada = elNuevoSer[elNuevoSer.Count - 1];


                if ((i[0] == coordenadaAnteriorPadre2[0] + 1) && (i[1] == coordenadaAnteriorPadre2[1]) && (i[2] == coordenadaAnteriorPadre2[2]))
                {
                    //añadir nueva al elNuevoSer
                    elNuevoSer.Add(new int[] { ultimaCoordenada[0] + 1, ultimaCoordenada[1], ultimaCoordenada[2] });
                    // Console.WriteLine("Agrego + X");
                }

                if ((i[0] == coordenadaAnteriorPadre2[0] - 1) && (i[1] == coordenadaAnteriorPadre2[1]) && (i[2] == coordenadaAnteriorPadre2[2]))
                {
                    elNuevoSer.Add(new int[] { ultimaCoordenada[0] - 1, ultimaCoordenada[1], ultimaCoordenada[2] });
                    // Console.WriteLine("Agrego -X");
                }

                if ((i[0] == coordenadaAnteriorPadre2[0]) && (i[1] == coordenadaAnteriorPadre2[1] + 1) && (i[2] == coordenadaAnteriorPadre2[2]))
                {
                    elNuevoSer.Add(new int[] { ultimaCoordenada[0], ultimaCoordenada[1] + 1, ultimaCoordenada[2] });
                    // Console.WriteLine("Agrego +Y");
                }

                if ((i[0] == coordenadaAnteriorPadre2[0]) && (i[1] == coordenadaAnteriorPadre2[1] - 1) && (i[2] == coordenadaAnteriorPadre2[2]))
                {
                    elNuevoSer.Add(new int[] { ultimaCoordenada[0], ultimaCoordenada[1] - 1, ultimaCoordenada[2] });
                    // Console.WriteLine("Agrego -Y");
                }
                if ((i[0] == coordenadaAnteriorPadre2[0]) && (i[1] == coordenadaAnteriorPadre2[1]) && (i[2] == coordenadaAnteriorPadre2[2] + 1))
                {
                    elNuevoSer.Add(new int[] { ultimaCoordenada[0], ultimaCoordenada[1], ultimaCoordenada[2]  + 1});
                    // Console.WriteLine("Agrego +Z");
                }
                if ((i[0] == coordenadaAnteriorPadre2[0]) && (i[1] == coordenadaAnteriorPadre2[1]) && (i[2] == coordenadaAnteriorPadre2[2] - 1))
                {
                    elNuevoSer.Add(new int[] { ultimaCoordenada[0], ultimaCoordenada[1], ultimaCoordenada[2] - 1 });
                    // Console.WriteLine("Agrego -Z");
                }
            }



            //  dibujar(elNuevoSer, this.texto, "El nuevo ser");

            for (int x = 0; x < elNuevoSer.Count - 1; x++)
            {
                for (int y = 1; y <= elNuevoSer.Count - 1; y++)
                {

                    if ((elNuevoSer[x][0] == elNuevoSer[y][0]) && (elNuevoSer[x][1] == elNuevoSer[y][1]) && (elNuevoSer[x][2] == elNuevoSer[y][2]))
                    {
                        //Console.WriteLine(x + " = " + y);
                        if (x != y)
                            bandera = false;
                    }

                }



            }//fin for

            //dibujar(elNuevoSer, this.texto, "El nuevo ser: " + bandera); 


            return bandera;
        }

        private List<int[]> unirSoluciones(List<int[]> padre1, List<int[]> padre2, string instruccion)
        {
            List<int[]> elNuevoSer = new List<int[]>();

            elNuevoSer.AddRange(padre1);

            int[] ultimaCoordenada = elNuevoSer[elNuevoSer.Count - 1];
            int[] coordenadaAnteriorPadre2 = padre2[0];

            // Console.WriteLine("Padre1: " + padre1.Count + ", Padre2: " + padre2.Count);


            if (instruccion == "arriba")
            {

                elNuevoSer.Add(new int[] { ultimaCoordenada[0], ultimaCoordenada[1] + 1, ultimaCoordenada[2] });

            }
            else if (instruccion == "abajo")
            {
                elNuevoSer.Add(new int[] { ultimaCoordenada[0], ultimaCoordenada[1] - 1, ultimaCoordenada[2] });

            }
            else if (instruccion == "derecha")
            {
                elNuevoSer.Add(new int[] { ultimaCoordenada[0] + 1, ultimaCoordenada[1], ultimaCoordenada[2] });

            }
            else if (instruccion == "izquierda")
            {
                elNuevoSer.Add(new int[] { ultimaCoordenada[0] - 1, ultimaCoordenada[1], ultimaCoordenada[2] });

            }
            else if (instruccion == "dentro")
            {
                elNuevoSer.Add(new int[] { ultimaCoordenada[0] + 1, ultimaCoordenada[1], ultimaCoordenada[2] + 1 });

            }
            else if (instruccion == "fuera")
            {
                elNuevoSer.Add(new int[] { ultimaCoordenada[0] + 1, ultimaCoordenada[1], ultimaCoordenada[2] - 1 });

            }

            int contador = 0;
            foreach (int[] i in padre2)
            {
                if (contador++ == 0)
                    continue;

                coordenadaAnteriorPadre2 = padre2[contador - 2];
                ultimaCoordenada = elNuevoSer[elNuevoSer.Count - 1];


                if ((i[0] == coordenadaAnteriorPadre2[0] + 1) && (i[1] == coordenadaAnteriorPadre2[1]) && (i[2] == coordenadaAnteriorPadre2[2]))
                {
                    //añadir nueva al elNuevoSer
                    elNuevoSer.Add(new int[] { ultimaCoordenada[0] + 1, ultimaCoordenada[1], ultimaCoordenada[2] });
                    // Console.WriteLine("Agrego + X");
                }

                if ((i[0] == coordenadaAnteriorPadre2[0] - 1) && (i[1] == coordenadaAnteriorPadre2[1]) && (i[2] == coordenadaAnteriorPadre2[2]))
                {
                    elNuevoSer.Add(new int[] { ultimaCoordenada[0] - 1, ultimaCoordenada[1], ultimaCoordenada[2] });
                    // Console.WriteLine("Agrego -X");
                }

                if ((i[0] == coordenadaAnteriorPadre2[0]) && (i[1] == coordenadaAnteriorPadre2[1] + 1) && (i[2] == coordenadaAnteriorPadre2[2]))
                {
                    elNuevoSer.Add(new int[] { ultimaCoordenada[0], ultimaCoordenada[1] + 1, ultimaCoordenada[2] });
                    // Console.WriteLine("Agrego +Y");
                }

                if ((i[0] == coordenadaAnteriorPadre2[0]) && (i[1] == coordenadaAnteriorPadre2[1] - 1) && (i[2] == coordenadaAnteriorPadre2[2]))
                {
                    elNuevoSer.Add(new int[] { ultimaCoordenada[0], ultimaCoordenada[1] - 1, ultimaCoordenada[2] });
                    // Console.WriteLine("Agrego -Y");
                }
                if ((i[0] == coordenadaAnteriorPadre2[0]) && (i[1] == coordenadaAnteriorPadre2[1]) && (i[2] == coordenadaAnteriorPadre2[2] + 1))
                {
                    elNuevoSer.Add(new int[] { ultimaCoordenada[0], ultimaCoordenada[1], ultimaCoordenada[2] + 1 });
                    // Console.WriteLine("Agrego +Z");
                }
                if ((i[0] == coordenadaAnteriorPadre2[0]) && (i[1] == coordenadaAnteriorPadre2[1]) && (i[2] == coordenadaAnteriorPadre2[2] - 1))
                {
                    elNuevoSer.Add(new int[] { ultimaCoordenada[0], ultimaCoordenada[1], ultimaCoordenada[2] - 1 });
                    // Console.WriteLine("Agrego -Z");
                }
            }

            return elNuevoSer;
        }

        public List<int[]> cruzar(List<int[]> padre1, List<int[]> padre2)
        {
            List<int[]> mitadPadre1 = new List<int[]>();
            List<int[]> mitadPadre2 = new List<int[]>();
            List<int[]> elMejor = new List<int[]>();
            List<int[]> elEngendroDelMal = new List<int[]>();
            elMejor.AddRange(padre1);
            string textoPadre1 = "";
            string textoPadre2 = "";
            int limite = 0;
            bool hayaMaldad = true;


            while (hayaMaldad)
            { //Si no se pudo con ninguna condicion entonces de nuevo intentara el corte en otro lado

                
                int cortePadre1 = generadorAleatorio.Next(padre1.Count - 2); //para que no salgan cadenas de 2
                int cortePadre2 = cortePadre1++;
                int contador = 0;

                mitadPadre1.Clear();
                mitadPadre2.Clear();


                foreach (int[] a in padre1)
                {

                    if (contador <= cortePadre1)
                        mitadPadre1.Add(a);
                    contador++;
                }

                contador = 0;

                foreach (int[] a in padre2)
                {

                    if (contador > cortePadre1)
                        mitadPadre2.Add(a);
                    contador++;
                }

                contador = 0;
                foreach (char a in texto)
                {

                    if (contador <= cortePadre1)
                        textoPadre1 += a;
                    else
                        textoPadre2 += a;

                    contador++;
                }

                contador = 1;

                while (contador < 24) //24 caras tiene el cubo
                {

                    if (contador == 4 || contador == 8)
                    {

                        List<int[]> mp2 = this.girarAbajo(mitadPadre2);
                        mitadPadre2.Clear();
                        mitadPadre2.AddRange(mp2);
                        mp2.Clear();
                        foreach (string s in instrucciones)
                        {
                           
                            if (esCompatible(mitadPadre1, mitadPadre2, s))
                            {
                                mp2.Clear();
                                mp2.AddRange(unirSoluciones(mitadPadre1, mitadPadre2, s));

                                if (evaluarCamino3D(mp2) <= evaluarCamino3D(elMejor))
                                {
                                    elMejor.Clear();
                                    elMejor.AddRange(mp2);
                                    hayaMaldad = false;
                                }
                            }
                        }//fin foreach instrucciones
                       

                    }
                    else if (contador == 12)
                    {

                        List<int[]> mp2 = this.girarHorario(mitadPadre2);
                        mitadPadre2.Clear();
                        mitadPadre2.AddRange(mp2);
                        mp2.Clear();

                        foreach (string s in instrucciones)
                        {
                            if (esCompatible(mitadPadre1, mitadPadre2, s))
                            {
                                mp2.Clear();
                                mp2.AddRange(unirSoluciones(mitadPadre1, mitadPadre2, s));

                                if (evaluarCamino3D(mp2) <= evaluarCamino3D(elMejor))
                                {
                                    elMejor.Clear();
                                    elMejor.AddRange(mp2);
                                    hayaMaldad = false;
                                }

                            }
                        }//fin foreach instrucciones


                    }
                    else if (contador == 16 || contador == 20)
                    {
                            List<int[]> mp2 = this.girarAntihorario(mitadPadre2);
                            mitadPadre2.Clear();
                            mitadPadre2.AddRange(mp2);
                            mp2.Clear();
                        foreach (string s in instrucciones)
                        {
                            

                            if (esCompatible(mitadPadre1, mitadPadre2, s))
                            {
                                mp2.Clear();
                                mp2.AddRange(unirSoluciones(mitadPadre1, mitadPadre2, s));

                                if (evaluarCamino3D(mp2) <= evaluarCamino3D(elMejor))
                                {
                                    elMejor.Clear();
                                    elMejor.AddRange(mp2);
                                    hayaMaldad = false;
                                }

                            }
                        }//fin foreach instrucciones
                    }
                    else
                    {
                        List<int[]> mp2 = new List<int[]>(this.girarIzquierda(mitadPadre2));
                        mitadPadre2.Clear();
                        mitadPadre2.AddRange(mp2);
                        mp2.Clear();

                        foreach (string s in instrucciones)
                        {
                            if (esCompatible(mitadPadre1, mitadPadre2, s))
                            {
                                mp2.Clear();
                                mp2.AddRange(unirSoluciones(mitadPadre1, mitadPadre2, s));

                                if (evaluarCamino3D(mp2) <= evaluarCamino3D(elMejor))
                                {
                                    elMejor.Clear();
                                    elMejor.AddRange(mp2);
                                    hayaMaldad = false;
                                }

                            }
                        }//fin foreach instrucciones
                       
                    }//else

                    contador++;
                }

                if (hayaMaldad)
                    limite++;

                if (limite == 100)
                    break;
            }// mientras haya maldad

            if (esConsistente(elMejor)){
                return elMejor;

            }

            else
            {
                return this.girarAbajo(padre1);

            }
                
        }

        public List<int[]> mejorSolucion()
        {

            List<int[]> elMachin = new List<int[]>();
            elMachin.AddRange(pueblo[0]);
            foreach (List<int[]> i in pueblo)
            {
                if (evaluarCamino3D(i) < evaluarCamino3D(elMachin))
                {
                    elMachin = new List<int[]>();
                    elMachin.AddRange(i);
                }
            }


            return elMachin;
        }

        public bool esConsistente(List<int[]> camino)
        {

            bool bandera = false;
            double valor = 0;

            for (int i = 0; i < camino.Count - 1; i++)
            {
              valor += Math.Sqrt(Math.Pow(camino[i][0] - camino[i + 1][0], 2) + Math.Pow(camino[i][1] - camino[i + 1][1], 2) + Math.Pow(camino[i][2] - camino[i + 1][2], 2)) ;


            }

            
            if (valor + 1 == camino.Count)
                return true;
            else
                return false;

        }
    }
}
